home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 21 / AACD 21.iso / AACD / Utilities / Ghostscript / src / gxdither.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-01  |  19.4 KB  |  579 lines

  1. /* Copyright (C) 1989, 1995, 1996, 1998, 1999 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of AFPL Ghostscript.
  4.   
  5.   AFPL Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author or
  6.   distributor accepts any responsibility for the consequences of using it, or
  7.   for whether it serves any particular purpose or works at all, unless he or
  8.   she says so in writing.  Refer to the Aladdin Free Public License (the
  9.   "License") for full details.
  10.   
  11.   Every copy of AFPL Ghostscript must include a copy of the License, normally
  12.   in a plain ASCII text file named PUBLIC.  The License grants you the right
  13.   to copy, modify and redistribute AFPL Ghostscript, but only under certain
  14.   conditions described in the License.  Among other things, the License
  15.   requires that the copyright notice and this notice be preserved on all
  16.   copies.
  17. */
  18.  
  19. /*$Id: gxdither.c,v 1.2 2000/09/19 19:00:36 lpd Exp $ */
  20. #include "gx.h"
  21. #include "gsstruct.h"
  22. #include "gsdcolor.h"
  23. #include "gxdevice.h"
  24. #include "gxlum.h"
  25. #include "gxcmap.h"
  26. #include "gxdither.h"
  27. #include "gzht.h"
  28.  
  29. /*
  30.  * Binary halftoning algorithms.
  31.  *
  32.  * The procedures in this file use halftoning (if necessary)
  33.  * to implement a given device color that has already gone through
  34.  * the transfer function.  There are two major cases: gray and color.
  35.  * Gray halftoning always uses a binary screen.  Color halftoning
  36.  * uses either a fast algorithm with a binary screen that produces
  37.  * relatively poor approximations, or a very slow algorithm with a
  38.  * general colored screen (or screens) that faithfully implements
  39.  * the Adobe specifications.
  40.  */
  41.  
  42. /* Tables for fast computation of fractional color levels. */
  43. /* We have to put the table before any uses of it because of a bug */
  44. /* in the VAX C compiler. */
  45. /* We have to split up the definition of the table itself because of a bug */
  46. /*  in the IBM AIX 3.2 C compiler. */
  47. private const gx_color_value q0[] = {
  48.     0
  49. };
  50. private const gx_color_value q1[] = {
  51.     0, frac_color_(1, 1)
  52. };
  53. private const gx_color_value q2[] = {
  54.     0, frac_color_(1, 2), frac_color_(2, 2)
  55. };
  56. private const gx_color_value q3[] = {
  57.     0, frac_color_(1, 3), frac_color_(2, 3), frac_color_(3, 3)
  58. };
  59. private const gx_color_value q4[] = {
  60.     0, frac_color_(1, 4), frac_color_(2, 4), frac_color_(3, 4),
  61.     frac_color_(4, 4)
  62. };
  63. private const gx_color_value q5[] = {
  64.     0, frac_color_(1, 5), frac_color_(2, 5), frac_color_(3, 5),
  65.     frac_color_(4, 5), frac_color_(5, 5)
  66. };
  67. private const gx_color_value q6[] = {
  68.     0, frac_color_(1, 6), frac_color_(2, 6), frac_color_(3, 6),
  69.     frac_color_(4, 6), frac_color_(5, 6), frac_color_(6, 6)
  70. };
  71. private const gx_color_value q7[] = {
  72.     0, frac_color_(1, 7), frac_color_(2, 7), frac_color_(3, 7),
  73.     frac_color_(4, 7), frac_color_(5, 7), frac_color_(6, 7), frac_color_(7, 7)
  74. };
  75.  
  76. /* We export fc_color_quo for the fractional_color macro in gzht.h. */
  77. const gx_color_value *const fc_color_quo[8] = {
  78.     q0, q1, q2, q3, q4, q5, q6, q7
  79. };
  80.  
  81. /* Render a gray, possibly by halftoning. */
  82. int
  83. gx_render_device_gray(frac gray, gx_color_value alpha, gx_device_color * pdevc,
  84.               gx_device * dev, gx_device_halftone * pdht,
  85.               const gs_int_point * ht_phase)
  86. {
  87.     bool cmyk = dev->color_info.num_components == 4;
  88.  
  89. /* Make a special check for black and white. */
  90.     if (alpha == gx_max_color_value) {
  91.     gx_color_value lum;
  92.  
  93.     switch (gray) {
  94.         case frac_0:
  95.         lum = 0;
  96.         goto bw;
  97.         case frac_1:
  98.         lum = gx_max_color_value;
  99.           bw:color_set_pure(pdevc,
  100.                    (cmyk ?
  101.                 gx_map_cmyk_color(dev, 0, 0, 0,
  102.                           gx_max_color_value - lum) :
  103.                 gx_map_rgb_color(dev, lum, lum, lum)));
  104.         return 0;
  105.         default:
  106.         ;
  107.     }
  108.     }
  109. /* get a few handy values */
  110.     {
  111.     uint max_value = dev->color_info.dither_grays - 1;
  112.     unsigned long hsize = (unsigned)pdht->order.num_levels;
  113.     unsigned long nshades = hsize * max_value + 1;
  114.     unsigned long lx = (nshades * gray) / (frac_1_long + 1);
  115.     uint v = lx / hsize;
  116.     gx_color_value lum = fractional_color(v, max_value);
  117.     gx_color_index color1;
  118.     int level = lx % hsize;
  119.  
  120.     /* The following should be a conditional expression, */
  121.     /* but the DECStation 3100 Ultrix 4.3 compiler */
  122.     /* generates bad code for it. */
  123. #define SET_COLOR_LUM(col, lum)\
  124.   if ( cmyk )\
  125.     col = gx_map_cmyk_color(dev, 0, 0, 0,\
  126.                    gx_max_color_value - lum);\
  127.   else if ( alpha == gx_max_color_value )\
  128.     col = gx_map_rgb_color(dev, lum, lum, lum);\
  129.   else\
  130.     col = gx_map_rgb_alpha_color(dev, lum, lum, lum, alpha)
  131.     SET_COLOR_LUM(color1, lum);
  132.     if_debug5('c', "[c]gray=0x%x --> (%d+%d/%lu)/%d\n",
  133.           (unsigned)gray, v, level, hsize, max_value + 1);
  134.     if (level == 0) {    /* Close enough to a pure color, */
  135.         /* no dithering needed. */
  136.         color_set_pure(pdevc, color1);
  137.         return 0;
  138.     } else {
  139.         gx_color_index color2;
  140.  
  141.         v++;
  142.         lum = fractional_color(v, max_value);
  143.         SET_COLOR_LUM(color2, lum);
  144.         color_set_binary_halftone(pdevc, pdht,
  145.                       color1, color2, level);
  146.         color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
  147.                 pdht->order.width,
  148.                 pdht->order.full_height);
  149.         return 1;
  150.     }
  151. #undef SET_COLOR_LUM
  152.     }
  153. }
  154.  
  155. /* 
  156.  *    Color dithering for Ghostscript.  The underlying device imaging model
  157.  *      supports dithering between two colors to generate intermediate shades.
  158.  *      
  159.  *      If the device has high quality colors (at least 32 values
  160.  *      per axis), we ask it to map the color directly.
  161.  *
  162.  *      Otherwise, things are a bit more complicated.  If the device 
  163.  *      supports N shades of each R, G and B independently, there are a total 
  164.  *      of N*N*N colors.  These colors form a 3-D grid in a cubical color 
  165.  *      space.  The following dithering technique works by locating the 
  166.  *      color we want in this 3-D color grid and finding the eight colors 
  167.  *      that surround it.  In the case of dithering into 8 colors with 1 
  168.  *      bit for each red, green and blue, these eight colors will always 
  169.  *      be the same.
  170.  *
  171.  *      Now we consider all possible diagonal paths between the eight colors
  172.  *      and chose the path that runs closest to our desired color in 3-D
  173.  *      color space.  There are 28 such paths.  Then we find the position
  174.  *      on the path that is closest to our color.
  175.  *
  176.  *      The search is made faster by always reflecting our color into
  177.  *      the bottom octant of the cube and comparing it to 7 paths.
  178.  *      After the best path and the best position on that path are found,
  179.  *      the results are reflected back into the original color space.
  180.  *
  181.  *      NOTE: This code has been tested for B/W and Color imaging with
  182.  *      1, 2, 3 and 8 bits per component.
  183.  *
  184.  *      --- original code by Paul Haeberli @ Silicon Graphics - 1990
  185.  *      --- extensively revised by L. Peter Deutsch, Aladdin Enterprises
  186.  *
  187.  *      lpd 3/14/94: added support for CMYK.
  188.  */
  189.  
  190. /*
  191.  * The weights are arbitrary, as long as their ratios are correct
  192.  * and they will fit into the difference between a ulong and a frac
  193.  * with room to spare.  By making WEIGHT1 and WEIGHT4 powers of 2,
  194.  * we can turn some multiplies into shifts.
  195.  */
  196. #define WNUM 128000
  197. #define    WEIGHT1        (ulong)(WNUM/1000)    /* 1.0                    */
  198. #define    WEIGHT2        (ulong)(WNUM/1414)    /* 1/sqrt(2.0)            */
  199. #define    WEIGHT3        (ulong)(WNUM/1732)    /* 1/sqrt(3.0)            */
  200. #define WEIGHT4        (ulong)(WNUM/2000)    /* 1/sqrt(4.0)            */
  201.  
  202. #define    DIAG_R        (0x1)
  203. #define    DIAG_G        (0x2)
  204. #define    DIAG_B        (0x4)
  205. #define DIAG_W        (0x8)
  206. #define    DIAG_RG        (0x3)
  207. #define    DIAG_GB        (0x6)
  208. #define    DIAG_BR        (0x5)
  209. #define    DIAG_RGB    (0x7)
  210. #define DIAG_RGBW    (0xf)
  211.  
  212. /* What should we do about the W/K component?  For the moment, */
  213. /* we ignore it in the luminance computation. */
  214. #define lum_white_weight 0
  215. private const unsigned short lum_w[16] =
  216. {
  217.     (0 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
  218.     (0 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
  219.     (0 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
  220.     (0 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
  221.     (1 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
  222.     (1 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
  223.     (1 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 0 * lum_white_weight),
  224.     (1 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 0 * lum_white_weight),
  225.     (0 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
  226.     (0 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight),
  227.     (0 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
  228.     (0 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight),
  229.     (1 * lum_blue_weight + 0 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
  230.     (1 * lum_blue_weight + 0 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight),
  231.     (1 * lum_blue_weight + 1 * lum_green_weight + 0 * lum_red_weight + 1 * lum_white_weight),
  232.     (1 * lum_blue_weight + 1 * lum_green_weight + 1 * lum_red_weight + 1 * lum_white_weight)
  233. };
  234.  
  235. /*
  236.  * Render RGB or CMYK, possibly by halftoning.  If we are rendering RGB,
  237.  * white is ignored.  If we are rendering CMYK, red/green/blue/white are
  238.  * actually cyan/magenta/yellow/black.
  239.  */
  240. int
  241. gx_render_device_color(frac red, frac green, frac blue, frac white, bool cmyk,
  242.     gx_color_value alpha, gx_device_color * pdevc, gx_device * dev,
  243.     gx_device_halftone * pdht, const gs_int_point * ht_phase)
  244. {
  245.     uint max_value = dev->color_info.dither_colors - 1;
  246.     uint num_levels = pdht->order.num_levels;
  247.     frac rem_r, rem_g, rem_b, rem_w;
  248.     uint r, g, b, w;
  249.     gx_color_value vr, vg, vb, vw;
  250.  
  251. #define MAP_COLOR_RGB()\
  252.   (alpha == gx_max_color_value ?\
  253.    gx_map_rgb_color(dev, vr, vg, vb) :\
  254.    gx_map_rgb_alpha_color(dev, vr, vg, vb, alpha))
  255. #define MAP_COLOR_CMYK()\
  256.   gx_map_cmyk_color(dev, vr, vg, vb, vw)
  257. #define MAP_COLOR()\
  258.   (cmyk ? MAP_COLOR_CMYK() : MAP_COLOR_RGB())
  259.  
  260.     /* Compute the quotient and remainder of each color component */
  261.     /* with the actual number of available colors. */
  262.     switch (max_value) {
  263.     case 1:        /* 8 or 16 colors */
  264.         if (red == frac_1)
  265.         rem_r = 0, r = 1;
  266.         else
  267.         rem_r = red, r = 0;
  268.         if (green == frac_1)
  269.         rem_g = 0, g = 1;
  270.         else
  271.         rem_g = green, g = 0;
  272.         if (blue == frac_1)
  273.         rem_b = 0, b = 1;
  274.         else
  275.         rem_b = blue, b = 0;
  276.         if (white == frac_1)
  277.         rem_w = 0, w = 1;
  278.         else
  279.         rem_w = white, w = 0;
  280.         break;
  281.     default:
  282.         {
  283.         ulong want_r, want_g, want_b, want_w;
  284.  
  285.         want_r = (ulong) max_value * red;
  286.         r = frac_1_quo(want_r);
  287.         rem_r = frac_1_rem(want_r, r);
  288.  
  289.         want_g = (ulong) max_value * green;
  290.         g = frac_1_quo(want_g);
  291.         rem_g = frac_1_rem(want_g, g);
  292.  
  293.         want_b = (ulong) max_value * blue;
  294.         b = frac_1_quo(want_b);
  295.         rem_b = frac_1_rem(want_b, b);
  296.  
  297.         want_w = (ulong) max_value * white;
  298.         w = frac_1_quo(want_w);
  299.         rem_w = frac_1_rem(want_w, w);
  300.         }
  301.     }
  302.  
  303.     /* Check for no dithering required */
  304.     if (!(rem_r | rem_g | rem_b | rem_w)) {
  305.     vr = fractional_color(r, max_value);
  306.     vg = fractional_color(g, max_value);
  307.     vb = fractional_color(b, max_value);
  308.     vw = fractional_color(w, max_value);
  309.     color_set_pure(pdevc, MAP_COLOR());
  310.     return 0;
  311.     }
  312.     if_debug12('c', "[c]rgbw=0x%x,0x%x,0x%x,0x%x -->\n   %x+0x%x,%x+0x%x,%x+0x%x,%x+0x%x -->\n",
  313.         (unsigned)red, (unsigned)green, (unsigned)blue, (unsigned)white,
  314.            (unsigned)r, (unsigned)rem_r, (unsigned)g, (unsigned)rem_g,
  315.            (unsigned)b, (unsigned)rem_b, (unsigned)w, (unsigned)rem_w);
  316.  
  317.     /* Dithering is required.  Choose between two algorithms. */
  318.  
  319.     if (dev->color_info.num_components >= 4) {
  320.     /* This is a CMYK device. */
  321.     /* Use the slow, general colored halftone algorithm. */
  322. #define RGB_REM(rem_v, i)\
  323.   (rem_v * (ulong)(pdht->components ? pdht->components[pdht->color_indices[i]].corder.num_levels : num_levels) / frac_1)
  324.     uint lr = RGB_REM(rem_r, 0), lg = RGB_REM(rem_g, 1),
  325.         lb = RGB_REM(rem_b, 2);
  326.  
  327.     if (cmyk)
  328.         color_set_cmyk_halftone(pdevc, pdht, r, lr, g, lg, b, lb,
  329.                     w, RGB_REM(rem_w, 3));
  330.     else
  331.         color_set_rgb_halftone(pdevc, pdht, r, lr, g, lg, b, lb, alpha);
  332. #undef RGB_REM
  333.     color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
  334.                 pdht->lcm_width, pdht->lcm_height);
  335.     if (!(pdevc->colors.colored.plane_mask &
  336.           (pdevc->colors.colored.plane_mask - 1))) {
  337.         /* We can reduce this color to a binary halftone or pure color. */
  338.         return gx_reduce_colored_halftone(pdevc, dev, cmyk);
  339.     }
  340.     return 1;
  341.     }
  342.     /* Fast, approximate binary halftone algorithm. */
  343.  
  344.     {
  345.     ulong hsize = num_levels;
  346.     int adjust_r, adjust_b, adjust_g, adjust_w;
  347.     gx_color_index color1;
  348.     frac amax, amin;
  349.     ulong fmax, cmax;
  350.     int axisc, facec, cubec, diagc;
  351.     unsigned short lum_invert;
  352.     ulong dot1, dot2, dot3, dot4;
  353.     int level;
  354.     int code;
  355.  
  356. /* Flip the remainder color into the 0, 0, 0 octant. */
  357.     lum_invert = 0;
  358. #define half (frac_1/2)
  359.     if (rem_r > half)
  360.         rem_r = frac_1 - rem_r,
  361.         adjust_r = -1, r++, lum_invert += lum_red_weight * 2;
  362.     else
  363.         adjust_r = 1;
  364.     if (rem_g > half)
  365.         rem_g = frac_1 - rem_g,
  366.         adjust_g = -1, g++, lum_invert += lum_green_weight * 2;
  367.     else
  368.         adjust_g = 1;
  369.     if (rem_b > half)
  370.         rem_b = frac_1 - rem_b,
  371.         adjust_b = -1, b++, lum_invert += lum_blue_weight * 2;
  372.     else
  373.         adjust_b = 1;
  374.     vr = fractional_color(r, max_value);
  375.     vg = fractional_color(g, max_value);
  376.     vb = fractional_color(b, max_value);
  377.     if (cmyk) {
  378.         if (rem_w > half)
  379.         rem_w = frac_1 - rem_w,
  380.             adjust_w = -1, w++, lum_invert += lum_white_weight * 2;
  381.         else
  382.         adjust_w = 1;
  383.         vw = fractional_color(w, max_value);
  384.         color1 = MAP_COLOR_CMYK();
  385.     } else
  386.         color1 = MAP_COLOR_RGB();
  387.  
  388. /* 
  389.  * Dot the color with each axis to find the best one of 15;
  390.  * find the color at the end of the axis chosen.
  391.  */
  392.     cmax = (ulong) rem_r + rem_g + rem_b;
  393.     dot4 = cmax + rem_w;
  394.     if (rem_g > rem_r) {
  395.         if (rem_b > rem_g)
  396.         amax = rem_b, axisc = DIAG_B;
  397.         else
  398.         amax = rem_g, axisc = DIAG_G;
  399.         if (rem_b > rem_r)
  400.         amin = rem_r, fmax = (ulong) rem_g + rem_b, facec = DIAG_GB;
  401.         else
  402.         amin = rem_b, fmax = (ulong) rem_r + rem_g, facec = DIAG_RG;
  403.     } else {
  404.         if (rem_b > rem_r)
  405.         amax = rem_b, axisc = DIAG_B;
  406.         else
  407.         amax = rem_r, axisc = DIAG_R;
  408.         if (rem_b > rem_g)
  409.         amin = rem_g, fmax = (ulong) rem_b + rem_r, facec = DIAG_BR;
  410.         else
  411.         amin = rem_b, fmax = (ulong) rem_r + rem_g, facec = DIAG_RG;
  412.     }
  413.     if (rem_w > amin) {
  414.         cmax = fmax + rem_w, cubec = facec + DIAG_W;
  415.         if (rem_w > amax)
  416.         fmax = (ulong) amax + rem_w, facec = axisc + DIAG_W,
  417.             amax = rem_w, axisc = DIAG_W;
  418.         else if (rem_w > fmax - amax)
  419.         fmax = (ulong) amax + rem_w, facec = axisc + DIAG_W;
  420.     } else
  421.         cubec = DIAG_RGB;
  422.  
  423.     dot1 = amax * WEIGHT1;
  424.     dot2 = fmax * WEIGHT2;
  425.     dot3 = cmax * WEIGHT3;
  426.     /*dot4 see above */
  427. #define use_axis()\
  428.   diagc = axisc, level = (hsize * amax + (frac_1_long / 2)) / frac_1_long
  429. #define use_face()\
  430.   diagc = facec, level = (hsize * fmax + frac_1_long) / (2 * frac_1_long)
  431. #define use_cube()\
  432.   diagc = cubec, level = (hsize * cmax + (3 * frac_1_long / 2)) / (3 * frac_1_long)
  433. #define use_tesseract()\
  434.   diagc = DIAG_RGBW, level = (hsize * dot4 + (2 * frac_1_long)) / (4 * frac_1_long)
  435.     if (dot1 > dot2) {
  436.         if (dot3 > dot1) {
  437.         if (dot4 * WEIGHT4 > dot3)
  438.             use_tesseract();
  439.         else
  440.             use_cube();
  441.         } else {
  442.         if (dot4 * WEIGHT4 > dot1)
  443.             use_tesseract();
  444.         else
  445.             use_axis();
  446.         }
  447.     } else {
  448.         if (dot3 > dot2) {
  449.         if (dot4 * WEIGHT4 > dot3)
  450.             use_tesseract();
  451.         else
  452.             use_cube();
  453.         } else {
  454.         if (dot4 * WEIGHT4 > dot2)
  455.             use_tesseract();
  456.         else
  457.             use_face();
  458.         }
  459.     };
  460.  
  461.     if_debug12('c', "   %x+0x%x,%x+0x%x,%x+0x%x,%x+0x%x; adjust=%d,%d,%d,%d\n",
  462.          (unsigned)r, (unsigned)rem_r, (unsigned)g, (unsigned)rem_g,
  463.          (unsigned)b, (unsigned)rem_b, (unsigned)w, (unsigned)rem_w,
  464.            adjust_r, adjust_g, adjust_b, adjust_w);
  465.  
  466.     if (level == 0) {
  467.         color_set_pure(pdevc, color1);
  468.         code = 0;
  469.     } else {
  470.         gx_color_index color2;
  471.  
  472. /* construct the second color, inverting back to original space if needed */
  473.         if (diagc & DIAG_R)
  474.         r += adjust_r;
  475.         if (diagc & DIAG_G)
  476.         g += adjust_g;
  477.         if (diagc & DIAG_B)
  478.         b += adjust_b;
  479. /* get the second device color, sorting by luminance */
  480.         vr = fractional_color(r, max_value);
  481.         vg = fractional_color(g, max_value);
  482.         vb = fractional_color(b, max_value);
  483.         if (cmyk) {
  484.         if (diagc & DIAG_W)
  485.             w += adjust_w;
  486.         vw = fractional_color(w, max_value);
  487.         color2 = MAP_COLOR_CMYK();
  488.         } else
  489.         color2 = MAP_COLOR_RGB();
  490.         if (level == num_levels) {    /* This can only happen through rounding.... */
  491.         color_set_pure(pdevc, color2);
  492.         code = 0;
  493.         } else {
  494.         if (lum_w[diagc] < lum_invert)
  495.             color_set_binary_halftone(pdevc, pdht, color2, color1, hsize - level);
  496.         else
  497.             color_set_binary_halftone(pdevc, pdht, color1, color2, level);
  498.         color_set_phase_mod(pdevc, ht_phase->x, ht_phase->y,
  499.                     pdht->order.width,
  500.                     pdht->order.full_height);
  501.         code = 1;
  502.         }
  503.     }
  504.  
  505.     if_debug7('c', "[c]diagc=%d; colors=0x%lx,0x%lx; level=%d/%d; lum=%d,diag=%d\n",
  506.           diagc, (ulong) pdevc->colors.binary.color[0],
  507.           (ulong) pdevc->colors.binary.color[1],
  508.           level, (unsigned)hsize, lum_invert, lum_w[diagc]);
  509.     return code;
  510.     }
  511. }
  512.  
  513. /* Reduce a colored halftone to a binary halftone or pure color. */
  514. int
  515. gx_reduce_colored_halftone(gx_device_color *pdevc, gx_device *dev, bool cmyk)
  516. {
  517.     int planes = pdevc->colors.colored.plane_mask;
  518.     gx_color_value max_color = dev->color_info.dither_colors - 1;
  519.     uint b[4];
  520.     gx_color_value v[4];
  521.     gx_color_index c0, c1;
  522.  
  523.     b[0] = pdevc->colors.colored.c_base[0];
  524.     v[0] = fractional_color(b[0], max_color);
  525.     b[1] = pdevc->colors.colored.c_base[1];
  526.     v[1] = fractional_color(b[1], max_color);
  527.     b[2] = pdevc->colors.colored.c_base[2];
  528.     v[2] = fractional_color(b[2], max_color);
  529.     if (cmyk) {
  530.     b[3] = pdevc->colors.colored.c_base[3];
  531.     v[3] = fractional_color(b[3], max_color);
  532.     c0 = dev_proc(dev, map_cmyk_color)(dev, v[0], v[1], v[2], v[3]);
  533.     } else
  534.     c0 = dev_proc(dev, map_rgb_color)(dev, v[0], v[1], v[2]);
  535.     if (planes == 0) {
  536.     /*
  537.      * Use a pure color.  This case is unlikely, but it can occur if
  538.      * (and only if) the difference of each component from the nearest
  539.      * device color is less than one halftone level.
  540.      */
  541.     color_set_pure(pdevc, c0);
  542.     return 0;
  543.     } else {
  544.     /* Use a binary color. */
  545.     int i = (planes >> 1) - (planes >> 3);  /* log2 for 1,2,4,8 */
  546.     uint bi = b[i] + 1;
  547.     const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
  548.     int index =
  549.         (pdht->components == 0 ? -1 : pdht->color_indices[i]);
  550.     /*
  551.      * NB: the halftone orders are all set up for an additive color
  552.      *     space.  To use these work with a cmyk color space, it is
  553.      *     necessary to invert both the color level and the color
  554.      *     pair. Note that if the original color was provided an
  555.      *     additive space, this will reverse (in an approximate sense)
  556.      *     the color conversion performed to express the color in cmyk
  557.      *     space.
  558.      */
  559.     bool invert = dev->color_info.num_components == 4; /****** HACK ******/
  560.     uint level = pdevc->colors.colored.c_level[i];
  561.  
  562.     v[i] = fractional_color(bi, max_color);
  563.     c1 = (cmyk ?
  564.           dev_proc(dev, map_cmyk_color)(dev, v[0], v[1], v[2], v[3]) :
  565.           dev_proc(dev, map_rgb_color)(dev, v[0], v[1], v[2]));
  566.     if (invert) {
  567.         level =
  568.         (index < 0 ? &pdht->order : &pdht->components[index].corder)
  569.           ->num_levels - level;
  570.         color_set_binary_halftone_component(pdevc, pdht, index, c1, c0,
  571.                         level);
  572.     } else
  573.         color_set_binary_halftone_component(pdevc, pdht, index, c0, c1, level);
  574.                         
  575.     return 1;
  576.     }
  577. }
  578.  
  579.